/*
 * $Id: LogEventObserverAndSender.java 21 2014-09-01 04:28:35Z ratking $
 *
 * Copyleft (C) 2014 RatKing. All wrongs reserved.
 */
package cn.ratking.demo.jaws7.jms;

import java.util.Date;

import javax.annotation.Resource;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.EventMetadata;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.inject.Inject;
import javax.jms.JMSConnectionFactory;
import javax.jms.JMSContext;
import javax.jms.JMSRuntimeException;
import javax.jms.Queue;
import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.omnifaces.util.Faces;
import org.slf4j.Logger;

import cn.ratking.demo.jaws7.model.LogEvent;

/**
 * 日志事件的观察者与JMS消息发送者
 *
 * @see http://docs.oracle.com/javaee/7/tutorial/doc/jms-concepts005.htm
 */
@ApplicationScoped
public class LogEventObserverAndSender {

    @Inject
    private transient Logger log;
    /** 日志事件的JMS上下文 */
    @Inject
    @JMSConnectionFactory("jms/LogEventQueueConnectionFactory")
    //@JMSSessionMode(JMSContext.AUTO_ACKNOWLEDGE)
    //@JMSPasswordCredential(userName = "admin", password = "mypassword")
    private JMSContext context;
    /** 日志事件的JMS队列 */
    @Resource(mappedName = "jms/LogEventQueue")
    private Queue logEventQueue;
//    /** 当前登录用户 */
//    @Inject
//    @Authenticated
//    private UcUser currentUser;

    /**
     * 观察日志事件，将其发送给JMS队列。
     *
     * @param logEvent 日志事件
     * @param meta 自动注入的事件元数据
     */
    public void sendLogEventToQueue(@Observes LogEvent logEvent, EventMetadata meta) {
        log.debug("Debug: LogEventObserverAndSender.sendLogEventToQueue(), context="
                + context + ", logEvent=" + logEvent + ", meta=" + meta);

        //The EventMetadata contains the following methods:
        // returns the InjectionPoint from which this event payload was fired, or null if it was fired from BeanManager.fireEvent(…).
        InjectionPoint injectionPoint = meta.getInjectionPoint();
        String declaringClass = null;
        if (injectionPoint != null) {
            declaringClass = injectionPoint.getMember().getDeclaringClass().getName();
            log.debug("Debug: declaringClass=" + declaringClass);
        }
//        String serverInfo = Faces.getServerInfo();
//        log.debug("Debug: serverInfo=" + serverInfo);

        if (logEvent.getLogLevel() <= 0) {
            logEvent.setLogLevel(LogEvent.LOGLEVEL_INFO);
        }
        if (logEvent.getLogType() <= 0) {
            logEvent.setLogType(LogEvent.LOGTYPE_APPLICATION);
        }
        Subject currentUser = SecurityUtils.getSubject();
        if (currentUser.getPrincipal() != null) {
            // 记录用户ID与用户名
            logEvent.setUserId(currentUser.getPrincipal().toString());
            // @todo 应改得更友好易读 (ratking 20140811)
            logEvent.setUserName(currentUser.getPrincipal().toString());
//        } else {
//            logEvent.setUserName("(匿名)");
        }
        // 记录用户IP地址
        logEvent.setClientIp(getRemoteAddr());
        logEvent.setEventSource(declaringClass);
        logEvent.setCreateTime(new Date());
        try {
            context.createProducer()
                    .setTimeToLive(300000) // 允许消息超时，设置生存时间为五分钟
                    .send(logEventQueue, logEvent);
            log.debug("观察日志事件，将其发送给JMS队列成功：" + logEvent);
        } catch (JMSRuntimeException jmse) {
            log.error("观察日志事件，将其发送给JMS队列异常：" + jmse.getMessage(), jmse);
            throw jmse;
        } // try-catch
    }

    /**
     * 获取客户端IP地址
     *
     * @return 客户端IP地址
     */
    protected String getRemoteAddr() {
        HttpServletRequest request = Faces.getRequest();
        if (request == null) {
            log.error("出错啦: LogEventObserverAndSender.getRemoteAddr(), request=" + request);
            return null;
        }

        log.debug("Debug: request.getHeader(\"X-Forwarded-For\")=" + request.getHeader("X-Forwarded-For"));
        log.debug("Debug: request.getHeader(\"x-forwarded-for\")=" + request.getHeader("x-forwarded-for"));

        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        } else {
            ip = ip.split("\\s*,\\s*", 2)[0]; // It's a comma separated string: client,proxy1,proxy2,...
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        log.debug("Debug: LogEventObserverAndSender.getRemoteAddr(), ip=" + ip);
        return ip;
    }
}
